#include "operacionConsulta.h"

std::string OperacionConsulta::NOMBRE_PARAM_CONSULTA = "CONSULTA";

OperacionConsulta::OperacionConsulta(std::string &archivo){
	this->nombre_archivo = archivo;
}

OperacionConsulta::~OperacionConsulta(){
	for (unsigned int i=0;i< campos.size();i++){
		if (campos[i]!= NULL) 
			delete campos[i];
	}
}

void OperacionConsulta::procesar_campos(std::string cadena,std::vector<ParesDatos*>& campos, TipoStruct* reg_base)
				throw(ExcepSintaxisParser){
	std::string aux = "[]";
	if ((cadena[0]==aux[0]) && (cadena[cadena.size()-1]==aux[1])){
		std::string nueva_cadena = cadena.substr(1, (cadena.size()-2)); 
		std::vector<std::string> params = Parser::obtener_campos(nueva_cadena);
		if (((params.size() % 2) == 0) && (params.size() >= 2)){
			int posicion = 0;
			int campo = 0;
			TipoDato* val = NULL;
			while ((posicion < (int)params.size())){
				if (Parser::convertir_a_int(params[posicion],campo)){
					if ((unsigned int)campo < reg_base->get_tamanio()){
					val = Parser::procesar_campo_impar(params[(posicion)+1],campo,reg_base);
					ParesDatos * p = new ParesDatos();
					p->set_numero_campo(campo);
					p->set_valor(val);
					campos.push_back(p);
					}
					else				
						throw ExcepSintaxisParser("Error - Numero de campo consultado no existente en el archivo");
				}
				else
					throw ExcepSintaxisParser("Error - El numero de campo debe ser un entero. RES = 0");
				posicion = posicion+2; 
			}
		}
		else   
			throw ExcepSintaxisParser("Error - Cantidad de parametros ingresados invalida. RES = 0");
	}
	else   
		throw ExcepSintaxisParser("Error - Ingreso de formato invalido, los parametros deben estar entre [ ]. RES = 0 ");
}

Operacion * OperacionConsulta::construir(std::string param) throw (ExcepSintaxisParser){
	OperacionConsulta * _return = NULL;
	if (Parser::procesar_nombre_operacion(param,NOMBRE_PARAM_CONSULTA)){
		//separo el nombre del resto de los parametros (separados por el ;)
		std::vector<std::string> params = Parser::split_parametros(param,';');
		if( params.size() == 2){
			std::string nombre_archivo;
			nombre_archivo = Parser::procesar_nombre(params[0]);//reviso el nombre del archivo
			//creo la CONSULTA
			_return = new OperacionConsulta(nombre_archivo);
			_return->datos = params[1];
		}
		else
			throw ExcepSintaxisParser("Error - Operacion CONSULTA, parametros invalidos");
	}
	return _return;				
}
		
bool OperacionConsulta::chequear_congruencia_datos(Archivo& arch) {
	TipoStruct* reg_base = arch.get_registro_base();
	bool result = true;
	unsigned int i= 0;	
	while((i<campos.size()) && (result)){
		if (campos[i]->get_numero_campo() < (int)reg_base->get_tamanio()) {
			TipoDato* dato_base = &((*reg_base)[campos[i]->get_numero_campo()]);
			TipoDato* dato = campos[i]->get_valor();
			if (dato_base->get_codigo_tipo() == STRUCT) {
				if (dato->get_tamanio()== 1){
					TipoStruct * aux = (TipoStruct *)(*((TipoColec*)dato))[0].clonar();	
					campos[i]->set_valor(aux);		
					delete dato;
				}
				else
					return false;
			}	
			result = (*reg_base)[campos[i]->get_numero_campo()].mismo_tipo(*(campos[i]->get_valor()));
		} else 
			result = false;
		i++;
	}
	return result;
}

void OperacionConsulta::ejecutar(Modelo* modelo){
	std::vector<TipoStruct*> resultado; 
	try{
		ArchivoDatos& arch = modelo->get_archivo(nombre_archivo);
		procesar_campos(datos,campos,arch.get_registro_base());
		if (chequear_congruencia_datos(arch)){
			arch.consultar(campos,resultado);
			std::string mensaje1 = imprimir_resultado(resultado);
			(*Logger::get_instance()) << mensaje1;
			( Debug::get_instance() )->mostrar_mensaje(mensaje1);
			limpiar_resultado(resultado);	
		}
		else { 
			std::string aux = "Error - Los datos no son congruentes con el formato del archivo. RES = 0"; 
			(*Logger::get_instance()) << aux;
			( Debug::get_instance() )->mostrar_mensaje(aux);
		}
	}catch (ExcepArchInexistente &e){
		std::string mensaje = "Error - Archivo "+nombre_archivo+" inexistente. RES = 0";
		(*Logger::get_instance()) << mensaje;
		( Debug::get_instance() )->mostrar_mensaje(mensaje);
	}	
}

std::string OperacionConsulta::imprimir_resultado(std::vector<TipoStruct*> &resultado){
	std::string result;
	if (resultado.size()!=0){
		std::stringstream ss; 
		ss << resultado.size();
		
		result = "Se consulto en el archivo "+nombre_archivo+" por registros con [valor,campo]. Se encontraron " + ss.str() + " elementos : ";
		for (unsigned int i=0; i< campos.size();i++){
			result.append("[");
			ss.str("");
			ss << (*(campos[i]->get_valor()));
			result += ss.str();
			result.append(",");
			ss.str("");
			ss << (campos[i]->get_numero_campo());
			result += ss.str();
			result.append("]");
			if (i< (campos.size()-1))
				result.append("--");
			}
		result.append(" . RES = ");
		for (unsigned int i=0; i< resultado.size(); i++){
			result.append("[");
			ss.str("");
			ss << (*(resultado[i]));
			result += ss.str();
			result.append("]");
			if (i< (resultado.size()-1))
				result.append("--");
		}
		result.append(".");
	}
	else{
		result = "No se encontraron resultados en el arhcivo "+nombre_archivo+" para la consulta realizada. RES = 0 ";
	}	

	return result;
}

void OperacionConsulta::limpiar_resultado(std::vector<TipoStruct*> &resultado){
	std::vector<TipoStruct*>::iterator it = resultado.begin();
	while (it != resultado.end()) {
		if ((*it) != NULL)
			delete(*it);
		it++;
	}
	resultado.clear();	
}
